cmake_minimum_required(VERSION 3.16)
####################################################################################################
# 1.会将CMakeLists.txt所处文件目录下的所有src/**/*.c文件加入为可执行文件
# 生成的可执行文件的名字规则如下:
# 假如项目根目录下有一文件 a/b/c/d.c, 则生成的文件名为a__b__c__d.c
#
#
# 2.多入口模式下会将当前要添加的.c执行文件 所处目录下的 `lib/`(如果该目录存在的话) 下的所有*.c文件合并进当前要添加的.c执行文件;
#   单入口模式下 则只会将 src/main.c 添加为可执行文件, src/**/* 下的所有其它.c文件则会被合并进 main 这个可执行文件中
#
#
# 3.会将当前要添加的.c执行文件 所处目录下的 `include/`(如果该目录存在的话) 下的所有(头)文件自动加载进当前工程的External Libraries中
#
#
# 4.可选择是否集成包管理工具 conan
####################################################################################################


#选择C标准版本
SET(CMAKE_C_STANDARD 11)

#########################
## 是否集成conan
## - 0: 为否
## - 1: 为是,使用conan profile为default
## - 2: 为是,使用conan profile为MinGW
#########################
SET(is_conan_project 0)

#########################
## 是否需要单独引入gtk gui库
## - 0: 为否
## - 1: 为是,并且会引入支持在`glade`(GTK+ 图形用户界面产生器)事件绑定的库 `gmodule-export-2.0`
## - 2: 为是,但不引入gmodule库
#########################
SET(need_gtk 1)

#########################
## 是否为单入口工程
## - 0: 不是单入口工程 则会搜索本CMakeLists.txt所处目录下的 **/*/*.c
## - 1: 为是,单入口工程prefix路径为src,且只能为src
#########################
SET(is_single_entry 1)

#最终生成的可执行文件的名字(只对单入口工程有效)
SET(custom_exe_name "test222")

####################################################################################################

GET_FILENAME_COMPONENT(project_id ${CMAKE_CURRENT_SOURCE_DIR} NAME)
STRING(REPLACE " " "_" project_id ${project_id})

PROJECT(${project_id})

SET(src_prefix src/)
if(NOT is_single_entry)
  SET(src_prefix "")
endif()

if(MSVC)
  SET(CMAKE_C_FLAGS "/utf-8") # 如果是msvc编译器 将默认采用的解码编码改为utf-8
endif()

SET(CMAKE_C_FLAGS_RELEASE -mwindows) # 如果是release编译出来的包 双击运行.exe时不会弹出windows命令行窗口

##################################################
## 引入 conan 对工程进行管理
##################################################

if(is_conan_project)
  if(MINGW)
    EXECUTE_PROCESS(COMMAND conan install .. --profile=mingw64 --build=missing WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE r_install)
  else()
    EXECUTE_PROCESS(COMMAND conan install .. --build=missing WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE r_install)
  endif()
  #MESSAGE("the result of conan install ${r_install}") #the result of conan install 0

  if(NOT r_install) # 说明command返回为0, 即脚本运行成功
    MESSAGE(STATUS "conan install success")
  else()
    MESSAGE(FATAL_ERROR "conan install failed")
  endif()

  INCLUDE(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
  conan_basic_setup()
endif()
##################################################


##################################################
## 为单独引入GTK GUI库做准备
##################################################
if(need_gtk)
  MESSAGE("CMAKE_MODULE_PATH is: ${CMAKE_MODULE_PATH}")
  #pkg-config is a helper tool used when compiling applications and libraries. It helps you insert the correct compiler options on the command line so an application can use gcc -o test test.c `pkg-config --libs --cflags glib-2.0` for instance, rather than hard-coding values on where to find glib (or other libraries). It is language-agnostic, so it can be used for defining the location of documentation tools, for instance.
  FIND_PACKAGE(PkgConfig REQUIRED)

  #PKG_CHECK_MODULES(GTK3 REQUIRED gtk+-3.0)
  #↑gtk+-3.0表示搜索大于等于3.0的gtk(3.0以后版本 都叫gtk+)
  #https://cmake.org/cmake/help/v3.6/module/FindPkgConfig.html
  #这里的设置的 GTK3 参数, 和后面我们使用的 ${GTK3_INCLUDE_DIRS} 等引入的变量的前缀有关联

  if (WIN32)
    SET(GTK_DEPS gtk+-3.0)
  elseif(APPLE)
    SET(GTK_DEPS gtk+-3.0 glib-2.0)
  else()
    SET(GTK_DEPS gtk+-3.0)
  endif ()

  if(need_gtk EQUAL 1)
    SET(GTK_DEPS ${GTK_DEPS} gmodule-export-2.0)
  endif()

  ###########################################################################################
  ## >https://www.gtk.org/docs/installations/windows/#setting-up-gtk-for-windows
  ## For windows:
  ## If you use mysys2, in order to import the gtk library,
  ## u should make sure u have installed mingw-w64-x86_64-gtk3 using the MYSYS2 pacman.
  ##
  ## If you use msvc, in order to import the gtk library,
  ## u should first use gvsbuild to install gtk instead --- https://github.com/wingtk/gvsbuild
  ##
  ##
  ## >https://www.gtk.org/docs/installations/linux/
  ## For linux ↑
  ###########################################################################################

  #message("GTK_DEPS:${GTK_DEPS}")
  foreach(dep ${GTK_DEPS})
    #message("dep:${dep}")
    PKG_CHECK_MODULES(${dep} REQUIRED ${dep})
  endforeach()
  #message("GTK3_CFLAGS_OTHER:${GTK3_CFLAGS_OTHER}")
  #↕等价 皆有效
  #message("gtk+-3.0_CFLAGS_OTHER:${gtk+-3.0_CFLAGS_OTHER}")

  foreach(dep ${GTK_DEPS})
    INCLUDE_DIRECTORIES(${${dep}_INCLUDE_DIRS})
    LINK_DIRECTORIES(${${dep}_INCLUDE_DIRS})
  endforeach()

  ADD_DEFINITIONS(${GTK3_CFLAGS_OTHER}) #编译gtk时需要的参数
endif()
##################################################


# file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/**/*.c")
# 这里的GLOB中 **/*.c只是列出当前所有子目录中匹配的文件(不包含当前目录下的.c)
# ,子目录的子目录则是需要 **/**/*.c
# ,子目录的子目录的子目录...

FILE(GLOB_RECURSE files "${CMAKE_CURRENT_SOURCE_DIR}/${src_prefix}*.c") # GLOB_RECURSE 会递归查找当前目录的所有递归子目录
#message("files: ${files}")
LIST(FILTER files EXCLUDE REGEX "${CMAKE_CURRENT_SOURCE_DIR}/cmake.*")
#message("files: ${files}")

foreach (file ${files})

  #message("file: ${file}")
  #[[if(${file} MATCHES "${project_id}/cmake-build-")
    message("this file is: ${file}. It's belong to cmake-build,we don't need to handle it")
    continue() # 我们不需要对构建产出文件再次进行处理
  endif()]]

  GET_FILENAME_COMPONENT(name ${file} NAME)
  #  message("name: ${name}")
  GET_FILENAME_COMPONENT(directory ${file} DIRECTORY)
  FILE(RELATIVE_PATH rp ${CMAKE_CURRENT_SOURCE_DIR} ${file})
  GET_FILENAME_COMPONENT(rp ${rp} DIRECTORY)
  #  message("rp: ${rp}") # 文件相对于工程根目录的相对路径(不包含当前文件,截至到上级目录)

  if ((NOT is_single_entry) AND (${directory} MATCHES "lib$"))
    #message("this file is ${file}. It's belong to a lib, we don't need to handle it")
    CONTINUE()
  endif ()

  if(is_single_entry AND (NOT ${name} STREQUAL "main.c"))
    #message("It's single_entry project, this file is ${file}. It's not called "main", we don't need to handle it")
    CONTINUE()
  endif()

  if (NOT ${rp} STREQUAL "")
    STRING(REPLACE "/" "__" rp ${rp})
    #message("replaced rp: ${rp}")
    SET(final_output_name "${rp}__${name}")
  else ()
    SET(final_output_name "${name}")
  endif ()

  if(EXISTS "${directory}/include")
    INCLUDE_DIRECTORIES("${directory}/include") # 自动#include指定目录里的文件
  endif()

  if(is_single_entry)
    if (custom_exe_name)
      SET(final_output_name "${custom_exe_name}")
    endif ()

    FILE(GLOB_RECURSE libs "${CMAKE_CURRENT_SOURCE_DIR}/${src_prefix}*.c")
    LIST(FILTER libs EXCLUDE REGEX "${CMAKE_CURRENT_SOURCE_DIR}/${src_prefix}main.c")
    if(NOT libs STREQUAL "")
      SET(all_lib_files "${libs}")
    endif()
  endif()

  # 添加可执行文件
  if (NOT is_single_entry AND (EXISTS "${directory}/lib"))
    # 如果当前要添加为可执行文件的.c文件所处当前目录下有lib目录
    # 则将该lib目录下的所有.c文件也一并追加进当前文件中进行编译
    #message("${file} has lib directory")
    FILE(GLOB_RECURSE all_lib_files "${directory}/lib/*.c") # 需要将当前要添加的.c执行文件 `lib/` 下的所有*.c文件加载进当前main文件
    ADD_EXECUTABLE(${final_output_name} ${file} ${all_lib_files}) # 如果后面跟了多个文件 则会将将多个文件编译到一个里 (一般是一个main文件和多个实现库文件)
  elseif(is_single_entry)
    # single_entry project 会将 src/**/* 下所有非 src/main.c 的文件合并进 src/main.c
    ADD_EXECUTABLE(${final_output_name} ${file} ${all_lib_files})
  else ()
    ADD_EXECUTABLE(${final_output_name} ${file})
  endif ()


  # 如果是conan工程 引入本工程中conan下载的库(conanfile.txt)
  if(is_conan_project)
    TARGET_LINK_LIBRARIES(${final_output_name} ${CONAN_LIBS})
  endif()

  # gtk库相关
  if(need_gtk)
    foreach(dep ${GTK_DEPS})
      TARGET_LINK_LIBRARIES(${final_output_name} ${${dep}_LIBRARIES})
    endforeach()
  endif()

  # WINDOWS下需要单独设置的
  if (WIN32)

  endif ()

  # 类UNIX系统下需要额外设置的
  if (UNIX OR Linux)
    TARGET_LINK_LIBRARIES(${final_output_name} pthread) # linux系统下实现的线程库叫pthread, 默认情况下并不会自动连接到我们的程序当中
  endif ()

  #  target_compile_definitions(${final_output_name} PUBLIC DEBUG) # 给所有产出的可执行文件在编译前定义一个宏 叫DEBUG 值没有写 默认为1
endforeach ()
